package org.springframework.howelly.model;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.springframework.binding.message.MessageContext;
import org.springframework.howelly.utils.Constants;
import org.springframework.howelly.utils.ReferenceData;
import org.springframework.howelly.validators.GastoValidator;
import org.springframework.webflow.execution.RequestContext;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Gasto implements Serializable {

    protected static final long serialVersionUID = 1171567558348174963L;

    protected Long id;

    protected String name;

    protected User user;

    protected Obra obra;

    protected Date date;

    protected Date diaEfectuado;

    protected String diaEfectuadoString = "";

    protected BigDecimal price;

    protected BigDecimal priceNeto;

    protected BigDecimal saldoParcial;

    protected String categoriaName;

    protected BigDecimal iva;

    protected String factura;

    protected String expenseType;

    private String cuit;

    private String numeroDeFactura;

    private boolean overrideCuit;

    public Gasto() {
    }

    public Gasto(Obra obra, User user) {
	this.obra = obra;
	this.user = user;
	Calendar calendar = Calendar.getInstance();
	setDate(ReferenceData.getDateTime());
	calendar.add(Calendar.DAY_OF_MONTH, 1);
	expenseType = Constants.GASTO;

    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
	return id;
    }

    public void setId(Long id) {
	this.id = id;
    }

    @Basic
    @Temporal(TemporalType.TIMESTAMP)
    public Date getDate() {
	return date;
    }

    public void setDate(Date datetime) {
	this.date = datetime;
    }

    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.LAZY)
    public Obra getObra() {
	return obra;
    }

    public void setObra(Obra obra) {
	this.obra = obra;
    }

    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.LAZY)
    public User getUser() {
	return user;
    }

    public void setUser(User user) {
	this.user = user;
    }

    public Gasto calculateSaldosInGasto(Obra obra, RequestContext context) {

	setPriceNeto(getPrice().subtract(getIva()).setScale(2, RoundingMode.HALF_DOWN));
	// el saldo es sobre el bruto
	setSaldoParcial(obra.getSaldo().subtract(getPrice()).setScale(2, RoundingMode.HALF_DOWN));
	// obra.setSaldo(getSaldoParcial());
	setObra(obra);
	return this;
    }

    // Validations
    public void validateGastoObra(MessageContext context) {
	GastoValidator.validateGastoObra(context, this);
    }

    // Getters and Setters
    @Override
    public String toString() {
	return "Gasto(" + user + "," + obra + ")";
    }

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }

    @Temporal(TemporalType.DATE)
    public Date getDiaEfectuado() {
	return diaEfectuado;
    }

    public void setDiaEfectuado(Date diaEfectuado) {

	this.diaEfectuado = diaEfectuado;
    }

    public String getDiaEfectuadoString() {
	return diaEfectuadoString;

    }

    public void setDiaEfectuadoString(String diaEfectuadoString) {
	this.diaEfectuadoString = diaEfectuadoString;
	DateFormat df = ReferenceData.getSimpleDateFormat();
	try {
	    setDiaEfectuado(df.parse(diaEfectuadoString));
	} catch (ParseException e) {
	    System.out.println("Esta parseando mal diaEfectuadoString");
	    e.printStackTrace();
	}
    }

    public String getCategoriaName() {
	return categoriaName;
    }

    public void setCategoriaName(String categoriaName) {
	this.categoriaName = categoriaName;
    }

    public BigDecimal getPrice() {
	return price;
    }

    public void setPrice(BigDecimal price) {
	this.price = price;
    }

    public BigDecimal getIva() {
	return iva;
    }

    public void setIva(BigDecimal iva) {
	if (getExpenseType().equals(Constants.GASTO))
	    this.iva = iva.setScale(2, RoundingMode.HALF_DOWN);
    }

    public String getFactura() {
	return factura;
    }

    public void setFactura(String factura) {
	this.factura = factura;
    }

    public BigDecimal getPriceNeto() {
	return priceNeto;
    }

    public void setPriceNeto(BigDecimal priceNeto) {
	this.priceNeto = priceNeto;
    }

    public BigDecimal getSaldoParcial() {
	return saldoParcial;
    }

    public void setSaldoParcial(BigDecimal saldoParcial) {
	this.saldoParcial = saldoParcial;
    }

    public String getExpenseType() {
	return expenseType;
    }

    public void setExpenseType(String expenseType) {
	this.expenseType = expenseType;
    }

    public static final Comparator<Gasto> ByDate = new Comparator<Gasto>() {
	public int compare(Gasto e1, Gasto e2) {
	    int dateCmp = -e2.getDiaEfectuado().compareTo(e1.getDiaEfectuado());
	    return dateCmp;
	}
    };
    public static final Comparator<Gasto> ByDateDesc = new Comparator<Gasto>() {
	public int compare(Gasto e1, Gasto e2) {
	    int dateCmp = e1.getDiaEfectuado().compareTo(e2.getDiaEfectuado());
	    return dateCmp;
	}
    };

    public String getCuit() {
	return cuit;
    }

    public void setCuit(String cuit) {
	this.cuit = cuit;
    }

    @Transient
    public boolean isOverrideCuit() {
	return overrideCuit;
    }

    public void setOverrideCuit(boolean overrideCuit) {
	this.overrideCuit = overrideCuit;
    }

    public String getNumeroDeFactura() {
	return numeroDeFactura;
    }

    public void setNumeroDeFactura(String numeroDeFactura) {
	this.numeroDeFactura = numeroDeFactura;
    }
}
